package com.jweb.framework.ws.server.http;

import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.web.servlet.FrameworkServlet;
import org.springframework.web.util.WebUtils;
import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.ws.support.DefaultStrategiesHelper;
import org.springframework.ws.transport.WebServiceMessageReceiver;
import org.springframework.ws.transport.http.WebServiceMessageReceiverHandlerAdapter;
import org.springframework.ws.transport.http.WsdlDefinitionHandlerAdapter;
import org.springframework.ws.wsdl.WsdlDefinition;

import com.jweb.framework.core.support.Utils;

/**
 * 修改人： Thomas
 * 修改内容：新增 
 * 类说明：webServices 作为请求方处理类
 */
public class WebServiceServlet extends FrameworkServlet {

	/**
	 * 
	 */
	private static final long serialVersionUID = -2171040310674602492L;
	
	public static final String DEFAULT_MESSAGE_FACTORY_BEAN_NAME = "messageFactory" ;
	public static final String DEFAULT_MESSAGE_RECEIVER_BEAN_NAME = "messageReceiver";
	public static final String DEFAULT_MESSAGE_RECEIVER_HANDLER_ADAPTER_BEAN_NAME = "messageReceiverHandlerAdapter" ;
	public static final String DEFAULT_WSDL_DEFINITION_HANDLER_ADAPTER_BEAN_NAME = "wsdlDefinitionHandlerAdapter" ;
	
	private final DefaultStrategiesHelper defaultStrategiesHelper ;
	private String messageFactoryBeanName = "messageFactory" ;
	private String messageReceiverHandlerAdapterBeanName = "messageReceiverHandlerAdapter";
	private WebServiceMessageReceiverHandlerAdapter messageReceiverHandlerAdapter ;
	private String wsdlDefinitionHandlerAdapterBeanName = "wsdlDefinitionHandlerAdapter";
	private WsdlDefinitionHandlerAdapter wsdlDefinitionHandlerAdapter ;
	private String messageReceiverBeanName = "messageReceiver";
	private WebServiceMessageReceiver messageReceiver ;
	private Map<String , WsdlDefinition> wsdlDefinitions ;
	private boolean transformWsdlLocations = true ;
	
	public WebServiceServlet(){
		Properties properties = new Properties();
		properties.put("org.springframework.ws.transport.WebServiceMessageReceiver", "org.springframework.ws.soap.server.SoapMessageDispatcher");
		properties.put("org.springframework.ws.WebServiceMessageFactory", "org.springframework.ws.soap.saaj.SaajSoapMessageFactory");
		this.defaultStrategiesHelper = new DefaultStrategiesHelper(properties);
	}
	
	public String getMessageFactoryBeanName(){
		return this.messageFactoryBeanName;
	}
	
	public void setMessageFactoryBeanName(String messageFactoryBeanName){
		this.messageFactoryBeanName = messageFactoryBeanName;
	}
	
	public String getMessageReceiverBeanName(){
		return this.messageReceiverBeanName ;
	}
	
	public void setMessageReceiverBeanName(String messageReceiverBeanName){
		this.messageReceiverBeanName = messageReceiverBeanName ;
	}
	
	public boolean isTransformWsdlLocations(){
		return this.transformWsdlLocations;
	}
	
	public String getMessageReceiverHandlerAdapterBeanName(){
		return this.messageReceiverHandlerAdapterBeanName ;
	}
	
	public void setMessageReceiverHandlerAdapterBeanName(String messageReceiverHandlerAdapterBeanName){
		this.messageReceiverHandlerAdapterBeanName = messageReceiverHandlerAdapterBeanName ;
	}
	
	public String getWsdlDefinitionHandlerAdapterBeanName(){
		return this.wsdlDefinitionHandlerAdapterBeanName ;
	}
	
	public void setWsdlDefinitionHandlerAdapterBeanName(String wsdlDefinitionHandlerAdapterBeanName) {
		this.wsdlDefinitionHandlerAdapterBeanName = wsdlDefinitionHandlerAdapterBeanName ;
	}
	
	public void setTransformWsdlLocation(boolean transformWsdlLocation){
		this.transformWsdlLocations = transformWsdlLocation ;
	}
	
	/**
	 * 统一分发
	 */
	@Override
	protected void doService(HttpServletRequest request , HttpServletResponse response) throws Exception {
		
		WsdlDefinition wsdlDefinition = getWsdlDefinition(request);
		if((wsdlDefinition != null) && (request.getParameter("wsdl") != null)){
			if("GET".equals(request.getMethod())){
				this.wsdlDefinitionHandlerAdapter.handle(request, response, wsdlDefinition);
				return ;
			}
			response.setStatus(405);
			this.logger.warn("wsdl just access by GET : " + request.getRequestURI());
			return ;
		}
		
		try {
			this.messageReceiverHandlerAdapter.handle(request, response, this.messageReceiver);
		} catch (Exception e) {
			if(Utils.shouldLogging(e)){
				this.logger.error("web service servlet error " , e);
			}
			throw e ;
		}
		catch (Error e){
			if(Utils.shouldLogging(e)){
				this.logger.error("web service servlet error " , e);
			}
			throw e ;
		}
		
	}
	
	public String getServletContextAttributeName(){
		return WebServiceServlet.class.getName() + ".CONTEXT." + getServletName();
	}
	
	/**
	 * 初始化
	 */
	protected void initFrameworkServlet() throws ServletException , BeansException {
		initMessageReceiverHandlerAdapter();
		initWsdlDefinitionHandlerAdapter();
		initMessageReceiver();
		initWsdlDefinitions();
	}
	
	
	protected long getLastModified(HttpServletRequest request) {
		WsdlDefinition wsdlDefinition = getWsdlDefinition(request);
		if((wsdlDefinition != null) && ("GET".equals(request.getMethod()))){
			return this.wsdlDefinitionHandlerAdapter.getLastModified(request, wsdlDefinition);
		}
		return this.messageReceiverHandlerAdapter.getLastModified(request, this.messageReceiver) ;
	}
	
	
	protected WebServiceMessageReceiver getMessageReceiver(){
		return this.messageReceiver ;
	}
	
	protected WsdlDefinition getWsdlDefinition(HttpServletRequest request){
		String str = WebUtils.extractFilenameFromUrlPath(request.getRequestURI());
		return this.wsdlDefinitions.get(str);
	}
	
	
	private void initMessageReceiverHandlerAdapter(){
		try {
			try {
				this.messageReceiverHandlerAdapter = getWebApplicationContext().getBean(getMessageReceiverHandlerAdapterBeanName() , WebServiceMessageReceiverHandlerAdapter.class) ;
				
			} catch (NoSuchBeanDefinitionException e) {
				this.messageReceiverHandlerAdapter = new WebServiceMessageReceiverHandlerAdapter() ;
			}
			
			initWebServiceMessageFactory();
			this.messageReceiverHandlerAdapter.afterPropertiesSet() ;
		} catch (Exception e) {
			throw new BeanInitializationException("Could not initialize WebServiceMessageReceiverHandlerAdapter" , e);
		}
	}
	
	
	private void initWebServiceMessageFactory() {
		WebServiceMessageFactory webServiceMessageFactory = null ;
		try {
			webServiceMessageFactory = getWebApplicationContext().getBean(getMessageFactoryBeanName() , WebServiceMessageFactory.class);
		} catch (NoSuchBeanDefinitionException e) {
			webServiceMessageFactory = this.defaultStrategiesHelper.getDefaultStrategy(WebServiceMessageFactory.class , getWebApplicationContext());
			
			if(this.logger.isDebugEnabled()){
				this.logger.debug("No WebServiceMessageFactory found in servlet '" + getServletName() + "' using default");
			}
		}
		this.messageReceiverHandlerAdapter.setMessageFactory(webServiceMessageFactory);
	}
	
	
	private void initWsdlDefinitionHandlerAdapter() {
		try {
			try {
				this.wsdlDefinitionHandlerAdapter = getWebApplicationContext().getBean(getWsdlDefinitionHandlerAdapterBeanName() , WsdlDefinitionHandlerAdapter.class);
			} catch (NoSuchBeanDefinitionException e) {
				this.wsdlDefinitionHandlerAdapter = new WsdlDefinitionHandlerAdapter() ;
			}
			this.wsdlDefinitionHandlerAdapter.setTransformLocations(isTransformWsdlLocations());
			this.wsdlDefinitionHandlerAdapter.afterPropertiesSet();
		} catch (Exception e) {
			throw new BeanInitializationException("Could not initialize WsdlDefinitionHandlerAdapter", e);
		}
	}
	
	private void initMessageReceiver() {
		try {
			this.messageReceiver = getWebApplicationContext().getBean(getMessageReceiverBeanName() , WebServiceMessageReceiver.class);
		} catch (NoSuchBeanDefinitionException e) {
			this.messageReceiver = this.defaultStrategiesHelper.getDefaultStrategy(WebServiceMessageReceiver.class , getWebApplicationContext());
			if(this.messageReceiver instanceof BeanNameAware){
				((BeanNameAware)this.messageReceiver).setBeanName(getServletName());
			}
			if(this.logger.isDebugEnabled()){
				this.logger.debug("No MessageDispatcher found in servlet '" + getServletName() + "':using default");
			}
		}
	}
	
	private void initWsdlDefinitions(){
		this.wsdlDefinitions = BeanFactoryUtils.beansOfTypeIncludingAncestors(getWebApplicationContext(), WsdlDefinition.class, true, false);
		if(this.logger.isDebugEnabled()){
			for(Iterator it = this.wsdlDefinitions.entrySet().iterator() ; it.hasNext() ; ){
				Map.Entry<String, WsdlDefinition> entry = (Map.Entry<String, WsdlDefinition>) it.next();
				String beanName =  entry.getKey();
				WsdlDefinition wsdlDefinition =  entry.getValue();
				this.logger.debug("Published [" + wsdlDefinition + "] as " + beanName + "?wsdl");
			}
		}
	}
	
	
	
	
	
	
	
	
	
	
	
	
	

}
